package com.ym.domain.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.extra.servlet.JakartaServletUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ym.domain.common.base.LoginUser;
import com.ym.domain.common.base.MedisValue;
import com.ym.domain.common.base.Result;
import com.ym.domain.common.constant.BusinessConst;
import com.ym.domain.common.constant.CacheKey;
import com.ym.domain.common.constant.MessageConst;
import com.ym.domain.common.constant.SymbolConst;
import com.ym.domain.common.util.ServletComUtil;
import com.ym.domain.common.util.SpringComUtil;
import com.ym.domain.common.util.StringComUtil;
import com.ym.domain.dao.CusCustomerService;
import com.ym.domain.event.LoginInfoEvent;
import com.ym.domain.model.CusCustomer;
import com.ym.domain.model.bo.CusRegisterBo;
import com.ym.domain.model.bo.LoginBo;
import com.ym.domain.service.CusCustomerBizService;
import com.ym.domain.service.MedisBizService;
import com.ym.domain.service.VerifyCodeBizService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class CusCustomerBizServiceImpl implements CusCustomerBizService {

    @Autowired
    CusCustomerService cusCustomerService;

    @Autowired
    MedisBizService mydisBizService;

    @Autowired
    VerifyCodeBizService verifyCodeBizService;

    @Override
    public Result registerCustomer(CusRegisterBo bo) {
        //判断手机号是否存在
        String errMsg = checkExistMobile(bo.getMobile());
        if (StringComUtil.isNotEmpty(errMsg)) {
            return Result.fail(errMsg, false);
        }

        //保存客户注册信息
        CusCustomer customer = new CusCustomer();
        customer.setCustomerId(getCustomerId());
        customer.setPhoneNumber(bo.getMobile());
        customer.setPassword(BCrypt.hashpw(bo.getPwd()));
        return cusCustomerService.save(customer) ? Result.success(true) : Result.fail(false);
    }

    public String checkExistMobile(String mobile) {
        CusCustomer existCustomer = cusCustomerService.getByPhoneNumber(mobile);
        if (null != existCustomer) {
            log.info("【客户注册】手机号({})已存在", mobile);
            return "手机号已存在";
        }
        return "";
    }

    private Integer getCustomerId() {
        int code = 15301;
        QueryWrapper<CusCustomer> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().orderByDesc(CusCustomer::getCustomerId).last("limit 1");
        CusCustomer one = cusCustomerService.getOne(queryWrapper);
        if (null != one) {
            code = one.getCustomerId() + 1;
        }
        return code;
    }

    @Override
    public Result login(LoginBo bo) {
        // 检查验证码
        String errMsg = checkVerifyCode(bo);
        if (StringComUtil.isNotEmpty(errMsg)) {
            return Result.fail(errMsg, false);
        }

        // 验证登录错误次数
        errMsg = checkLoginErrCount(bo.getMobile());
        if (StringComUtil.isNotEmpty(errMsg)) {
            return Result.fail(errMsg, false);
        }

        // 查询客户是否存在
        CusCustomer customer = cusCustomerService.getByPhoneNumber(bo.getMobile());
        if (null == customer) {
            return Result.fail(MessageConst.ERR_LOGIN_USERNAME_PWD, false);
        }

        // 验证密码是否正确
        if (!checkPwd(customer.getPassword(), bo.getPwd())) {
            setLoginErrCount(bo.getMobile());
            return Result.fail(MessageConst.ERR_LOGIN_USERNAME_PWD, false);
        }

        // 登录
        Long customerId = Long.parseLong(customer.getCustomerId().toString());
        String phoneNumber = customer.getPhoneNumber();

        String token = setLoginInfo(customerId, phoneNumber, LoginUser.USER_TYPE_CUSTOMER);
        clearLoginCacheInfo(bo);

        // 保存登录信息
        saveLoginInfo(bo.getMobile(), LoginUser.USER_TYPE_CUSTOMER, MessageConst.LOGIN_MSG_SUCCESS);

        return Result.success(token);

    }

    private String checkVerifyCode(LoginBo bo) {
        MedisValue medisValue = verifyCodeBizService.getVerifyCode(bo.getVerifyUuid());
        log.info("【登录】验证码校验信息,登录输入项 : {}, 缓存项信息: {}", bo, medisValue);
        if (medisValue.isExpired()) {
            return MessageConst.ERR_VERIFY_CODE_TIMEOUT;
        }
        String orgiVerifyCode = medisValue.getValue();
        if (StringUtils.isBlank(orgiVerifyCode)) {
            return MessageConst.ERR_VERIFY_CODE_FAILURE;
        }
        String verifyCode = bo.getVerifyCode();
        if (!verifyCode.equals(orgiVerifyCode)) {
            return MessageConst.ERR_VERIFY_CODE_FAILURE;
        }
        return null;
    }

    private String checkLoginErrCount(String mobile) {
        String key = CacheKey.LOGIN_ERR_COUNT + mobile;

        MedisValue medisValue = mydisBizService.get(key);
        if (medisValue.isExpired() || null == medisValue.getValue()) {
            return null;
        }

        int errCount = Integer.parseInt(medisValue.getValue());
        if (errCount >= 6) {
            return MessageConst.ERR_LOGIN_ERR_MANY_TIMES;
        }
        return null;
    }

    private boolean checkPwd(String hashPwd, String inputPwd) {
        return BCrypt.checkpw(inputPwd, hashPwd);
    }

    private void setLoginErrCount(String mobile) {
        // 登录错误次数+1
        String key = CacheKey.LOGIN_ERR_COUNT + mobile;
        MedisValue medisValue = mydisBizService.get(key);
        String value = medisValue.getValue();
        if (StringUtils.isBlank(value)) {
            mydisBizService.put(key, "1", 60 * 60 * 8L);
        } else {
            int errCount = Integer.parseInt(value);
            mydisBizService.put(key, String.valueOf(++errCount), 60 * 60 * 8L);
        }
    }

    private String setLoginInfo(Long userId, String mobile, String userRoleType) {
        // 登录成功，设置登录信息
        LoginUser loginUser = new LoginUser(userId, userRoleType, mobile);

        String loginId = userRoleType + SymbolConst.UNDERLINE + userId;
        StpUtil.login(loginId);
        StpUtil.getSession().set(BusinessConst.LOGIN_USER, loginUser);
        return StpUtil.getTokenValue();
    }

    private void clearLoginCacheInfo(LoginBo bo) {
        // 清除验证码
        mydisBizService.remove(getRequestIp() + SymbolConst.UNDERLINE + bo.getVerifyUuid());

        // 删除登录错误次数
        mydisBizService.remove(CacheKey.LOGIN_ERR_COUNT + bo.getMobile());
    }

    private void saveLoginInfo(String mobile, String roleType, String msg) {
        HttpServletRequest request = ServletComUtil.getRequest();
        LoginInfoEvent loginInfoEvent = LoginInfoEvent.builder().mobile(mobile).roleType(roleType).msg(msg).request(request).build();
        SpringComUtil.context().publishEvent(loginInfoEvent);
    }

    private String getRequestIp() {
        HttpServletRequest request = ServletComUtil.getRequest();
        if (request != null) {
            return JakartaServletUtil.getClientIP(request);
        }
        return "未知";
    }

    // ------------------------------- 以下为测试 -------------------------------

    @Override
    public void mydis() {
        String key = "a1";
        String value = "11111";

        log.info("【缓存】put(key, value)方法 key={}, value={}, 结果={}", key, value, mydisBizService.put(key, value));
        log.info("【缓存】get方法 key={}, value={}", key, mydisBizService.get(key));

        key = "123";
        value = "890";
        log.info("【缓存】put(key, value,expired)方法 key={}, value={}, 结果={}", key, value, mydisBizService.put("123", "890", 10L));

        key = "abc2";
        log.info("【缓存】remove方法 key={}, 结果={}", key, mydisBizService.remove(key));

        key = "123";
        log.info("【缓存】isExpired方法 key={}, 结果={}", key, mydisBizService.isExpired(key));

    }

}
